|
|
Fatigue Evaluation - Evolution of Median Power Frequency |
| Tags | process/\emg |
In contrast to the cardiac muscle, skeletal muscles are very susceptible to fatigue when exposed to an intense activity, for example, during a sports practice.
Fatigue
can be defined as a complex physiological phenomenon with several causes and dependent of different mechanisms (accordingly to Cifrek et. al.
).
Fatigue may have serious consequences, being one triggering phenomenon behind muscular injuries.
So, taking into account the relevance of this phenomenon, fatigue study and monitoring is a promising research area, with some decades. During this period, it was demonstrated that some parameters extracted from EMG signal evolve in a particular way as fatigue is being acquired.
One of this parameters, and probably the most consensual one, is the median power frequency
, that decreases along fatigue acquisition, i.e. the power spectrum suffers a compression to lowest frequency components
.
In this Jupyter Notebook it will be presented the basic methodology to monitoring the fatigue along time.
1 - Importation of the needed packages
# OpenSignals Tools own package for loading and plotting the acquired data
import opensignalstools as ost
import opensignalstools.signal_samples as signal_samples
# Scientific packages
from numpy import linspace, where
from scipy.signal import periodogram
from scipy.integrate import cumtrapz
2 - Load of acquired EMG data, collected during a fatigue induction trial (*biceps brachii* isometric contraction)
# Load of data
data, header = signal_samples.load_signal("emg_fatigue")
3 - Mac address identification for the device and the channel used during acquisition
mac_address = list(header.keys())[0]
channel = "CH" + str(header[mac_address]["channels"][0])
print ("Mac Address: " + str(mac_address) + " Channel: " + str(channel))
4 - Sampling rate and acquired data samples storage (inside variables)
# Sampling rate and acquired data
sr = header[mac_address]["sampling rate"]
device = header[mac_address]["device"]
resolution = header[mac_address]["resolution"][0]
# Signal Samples
signal = data[mac_address][channel]
time = linspace(0, len(signal) / sr, len(signal))
5 - Muscular activations detection
Each muscular activation defines a processing window# The default call of detect_emg_activations function is:
# detect_emg_activations(emg_signal, sample_rate, smooth_level=20, threshold_level=10, time_units=False, volts=False,
# resolution=None, device="biosignalsplux", plot_result=False)
# This function returns the samples where each activation period starts and ends (first two outputs, reason why it is specified
# [:2]) the smoothed EMG signal samples and threshold level. Samples above the threshold are converted to 1 and the samples
# below to 0, which give rise to a rectangular activation signal.
activation_begin, activation_end = ost.detect_emg_activations(signal, sr)[:2]
ost.detect_emg_activations previous call has explicit and implicit arguments. The list containing the signal samples collected during the acquisition and the sampling rate at which the acquisition was carried out are the explicit ones, while smoothLevel and thresholdLevel correspond to implicit arguments that assume predefined values of 20 % and 10 %, respectively.
Changing these two parameters will produce changes in the detection of muscular activations, as can be seen at the following figure.
ost.plot_compare_act_config(signal, sr)
6 - Extraction of the Median Power Frequency that characterises each muscular activation (processing window)
The Median Power Frequency is defined as the frequency value that allows the power spectrum division into two regions with equal power\begin{equation} \int_0^{f_{median}} PSD(f) df = \frac{1}{2} \int_0^{sr/2} PSD(f) df \end{equation} where $f_{median}$ defines the median power frequency, $PSD(f)$ is the power spectral density estimate, after decomposing the signal by applying the Fourier Transform, for the elementary component with frequency f. The term $sr$ refers to the "sampling rate" abbreviation.
# Iteration along muscular activations
median_freq_data = []
median_freq_time = []
for activation in range(0, len(activation_begin)):
processing_window = signal[activation_begin[activation]:activation_end[activation]]
central_point = (activation_begin[activation] + activation_end[activation]) / 2
median_freq_time += [central_point / sr]
# Processing window power spectrum (PSD) generation
freqs, power = periodogram(processing_window, fs=sr)
# Median power frequency determination
area_freq = cumtrapz(power, freqs, initial=0)
total_power = area_freq[-1]
median_freq_data += [freqs[where(area_freq >= total_power / 2)[0][0]]]
# The previous indexation [0][0] was specified in order to only the first sample that verifies
# the condition area_freq >= total_power / 2 be returned (all the subsequent samples will verify
# this condition, but, we only want the frequency that is nearest to the ideal frequency value
# that divides power spectrum into to regions with the same power - which is not achievable in
# a digital processing perspective).
7 - Graphical Representation of the Median Frequency evolution time series
This procedure can be automatically done by fatigue_eval_med_freq function in extract module of opensignalstools package
ost.fatigue_eval_med_freq(signal, sr)